package com.hotlcc.bark.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.eatthepath.pushy.apns.*;
import com.eatthepath.pushy.apns.util.SimpleApnsPayloadBuilder;
import com.eatthepath.pushy.apns.util.SimpleApnsPushNotification;
import com.eatthepath.pushy.apns.util.concurrent.PushNotificationFuture;
import com.hotlcc.bark.common.config.properties.ApnsClientProperties;
import com.hotlcc.bark.common.util.CommonUtil;
import com.hotlcc.bark.service.ApplePushService;
import com.hotlcc.bark.service.DevicesService;
import com.hotlcc.bark.service.dto.DevicesDTO;
import com.hotlcc.bark.service.dto.PushParamsDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.util.unit.DataSize;

import java.nio.charset.Charset;
import java.util.Date;

@Service
@Slf4j
public class ApplePushServiceImpl implements ApplePushService {
    @Autowired
    private ApnsClient apnsClient;
    @Autowired
    private ApnsClientProperties apnsClientProperties;
    @Autowired
    private DevicesService devicesService;

    @Override
    public void push(String deviceKey,
                     String category, String title, String body,
                     PushParamsDTO pushParams) {
        Assert.notBlank(deviceKey, "device key is empty");

        DevicesDTO devicesDTO = devicesService.queryOne(deviceKey);
        Assert.notNull(devicesDTO, "failed to get device token: not exists");

        String payload = new SimpleApnsPayloadBuilder()
            .setMutableContent(true)
            .setAlertTitle(StrUtil.blankToDefault(title, null))
            .setAlertBody(StrUtil.blankToDefault(body, "NoContent"))
            .setSound(StrUtil.isNotBlank(pushParams.getSound()) ? (StrUtil.endWith(pushParams.getSound(), ".caf") ? pushParams.getSound() : StrUtil.format("{}.caf", pushParams.getSound())) : null)
            .setCategoryName(StrUtil.blankToDefault(category, "myNotificationCategory"))
            .setBadgeNumber(pushParams.getBadge())
            .addCustomProperty("url", StrUtil.blankToDefault(pushParams.getUrl(), null))
            .addCustomProperty("level", StrUtil.blankToDefault(pushParams.getLevel(), "active"))
            .addCustomProperty("devicekey", StrUtil.blankToDefault(deviceKey, null))
            .addCustomProperty("group", StrUtil.blankToDefault(pushParams.getGroup(), null))
            .addCustomProperty("isarchive", pushParams.getIsArchive())
            .addCustomProperty("icon", StrUtil.blankToDefault(pushParams.getIcon(), null))
            .addCustomProperty("copy", StrUtil.blankToDefault(pushParams.getCopy(), null))
            .addCustomProperty("autocopy", pushParams.getAutoCopy())
            .build();

        Assert.isTrue(DataSize.ofBytes(StrUtil.byteLength(payload, Charset.defaultCharset())).compareTo(apnsClientProperties.getPayloadMaximum()) <= 0, "消息大小超出限制");

        ApnsPushNotification notification = new SimpleApnsPushNotification(devicesDTO.getToken(), apnsClientProperties.getTopic(), payload, DateUtil.offsetDay(new Date(), 1).toInstant(), DeliveryPriority.IMMEDIATE, PushType.ALERT);

        PushNotificationFuture<ApnsPushNotification, PushNotificationResponse<ApnsPushNotification>> future = apnsClient.sendNotification(notification);
        PushNotificationResponse<ApnsPushNotification> response = CommonUtil.futureGet(future);

        Assert.isTrue(response.getStatusCode() == HttpStatus.OK.value(), response.getRejectionReason().map(r -> StrUtil.format("push failed: {}", r)).orElse("push failed"));
    }
}
